const fs = require("fs");
const path = require("path");
const EventEmitter = require("events").EventEmitter;

class WriteStream extends EventEmitter {
  constructor(path, options) {
    super();
    this.path = path;
    this.highWaterMark = options.highWaterMark || 16 * 1024;
    this.encoding = options.encoding || "utf8";
    this.start = options.start || 0;
    this.mode = options.mode || 0o666;
    this.flags = options.flags || "w";

    // 定义缓存区
    this.cache = [];
    this.writing = false; //是否正在写入
    this.cacheWriteLength = 0;
    this.needDrain = false; // 只有写入的内容大于等于highWaterMark needDrain = true
    this.offset = this.start; //每次写入的偏移量
    this.hadClose = false; //

    // 先打开文件
    this.open();
  }
  open() {
    fs.open(path.resolve(__dirname, this.path), this.flags, (err, fd) => {
      this.fd = fd;
      this.emit("open", fd);
    });
  }
  write(chunk, encoding = this.encoding, callback) {
    //同步调用write方法
    // 调用write方法时，现在判断当前是否正在写入，如果正在写入则放入缓存，如果不是则需要真正的写入文件
    console.log("write", this.fd);
    // 先判断chunk是不是buffer类型
    chunk = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
    this.cacheWriteLength += chunk.length; //统计写入的数据的个数
    let flag = this.cacheWriteLength < this.highWaterMark;
    this.needDrain = !flag; //写入的内容大于highWaterMark的值，
    // 判断当前是否正在写
    if (this.writing) {
      //如果是正在写入，追加到内存中
      this.cache.push({
        chunk,
        encoding,
        callback,
      });
    } else {
      this.writing = true;
      // 真实写入
      this._write(chunk, encoding, () => {
        callback && callback();
        this.clearBuffer();
      });
    }
    return flag;
  }
  _write(chunk, encoding, callback) {
    if (typeof this.fd !== "number") {
      return this.once("open", () => this._write(chunk, encoding, callback));
    }
    // console.log(this.fd);
    // 获取到fd后，可以执行写入操作
    /* 
        this.fd：文件描述符
        chunk: 写入的buffer数据
        0: 表示数据的第0个位置开始写入, 
        chunk.length：写入buffer多少个字节
        this.offset: 写入文件的偏移量
    */
    fs.write(
      this.fd,
      chunk,
      0,
      chunk.length,
      this.offset,
      (err, bytesWrite) => {
        // bytesWrite真实写入的数据，增加偏移量
        this.offset += bytesWrite;
        // 减少缓存的空间长度
        this.cacheWriteLength -= bytesWrite;
        callback();
      }
    );
  }
  end(chunk, encoding) {
    // console.log(this.cacheWriteLength, this.cache, "---");

    if (chunk && !this.hadClose) {
      return this.write(chunk, encoding, () => this.close());
    }
    this.close();
  }
  close() {
    this.hadClose = true;
    fs.close(this.fd, () => {
      this.emit("close");
    });
  }
  // 清空队列中的第一个
  clearBuffer() {
    // 从缓存中取数据
    let obj = this.cache.shift();
    if (obj) {
      this._write(obj.chunk, obj.encoding, () => {
        obj.callback && obj.callback();
        this.clearBuffer();
      });
    } else {
      if (this.needDrain) {
        this.needDrain = false; // 清空了内容，下次重新判断是否需要触发drain事件
        this.writing = false; //下次往文件中写数据
        this.emit("drain");
      }
    }
  }
}

module.exports = WriteStream;
